[1 sentence description of data type (modeled or gage)…and source and purpose.]
Station IDs follow a 3-character alphanumeric format. When the ID is known, the station metadata can be looked up using the following URL pattern:
https://cdec.water.ca.gov/dynamicapp/staMeta?station_id={XXX}
CDEC has an interactive station locator map located at https://cdec.water.ca.gov/webgis/?appid=cdecstation
Stations can also be queried by river basin. For the greater Sacramento-San Joaquin basin, this includes the following river basins:
river_basins <- read_csv("cdec_river_basins.csv")
river_basins |> filter(selected) |> pull(river_basin) |> paste(collapse=", ") |> cat()
## AMERICAN RIVER, BATTLE CREEK, BEAR RIVER, BUTTE CREEK, CACHE CREEK, CALAVERAS RIVER, COSUMNES RIVER, COTTONWOOD CREEK, DELTA, FEATHER RIVER, KERN RIVER, KINGS RIVER, MC CLOUD RIVER, MERCED RIVER, MOKELUMNE RIVER, PIT RIVER, PUTAH CREEK, SACRAMENTO RIVER, SACTO VLY NE, SACTO VLY WEST, SAN JOAQUIN FLOOR, SAN JOAQUIN RIVER, SAN JOAQUIN VLY WEST, STANISLAUS RIVER, STONY CREEK, TUOLUMNE RIVER, YUBA RIVER
Refer to the station ID for which sensors are available at a particular station.
Following are the sensor codes that report some variation of flow in cfs. There are many other codes not listed here including stage, temperature, turbidity, etc.
Codes for standard in-stream flow, mapped and summarized in this report for mainstems:
20 = FLOW = FLOW,
RIVER DISCHARGE, CFS*41 = MFLOW = FLOW,
MEAN DAILY, CFS*Codes for other flow (cfs) sensors in the CDEC database:
110 = DIVERSN = FLOW,
CANAL DIVERSION, CFS*23 = OUTFLOW =
RESERVOIR OUTFLOW, CFS*76 = INFLOW =
RESERVOIR INFLOW, CFS7 = REL SCH =
SCHEDULED RELEASE, CFS (manually reported)210 = AUXFLOW = FLOW
AUX, CFS165 = FLOW.XX = FLOW,
RIVER DISCHARGE PRECISE, CFS (rarely used)8 = FNF = FULL
NATURAL FLOW, CFS (modeled)*sensors indicated are also shown on the map for context but are not included in the summary stats for this report
A particular station sensor will have data available at one or more of these duration types. The station lookup page will describe which sensor-duration combinations are available.
E = EVENT (typically
15-minute intervals)H = HOURLYD = DAILYFor example, BCK
has flow data (sensor 20) available at the 15-minute
(duration E) and hourly (duration H)
timesteps, as well as in a summarized daily mean format (sensor
41, duration D).
Data can be queried in CSV format using the following URL template, including the 3-digit station ID, the sensor and duration codes described above, and the start and end dates.
https://cdec.water.ca.gov/dynamicapp/req/CSVDataServlet?Stations={XXX}&SensorNums={XX}&dur_code={X}&Start={YYYY-MM-DD}&End={YYYY-MM-DD}
Data can be queried via the CDEC API. This is documented in PDFs linked at https://cdec.water.ca.gov/queryTools.html
Real-time, daily, monthly query options are available at the following link: https://cdec.water.ca.gov/queryTools.html
An alternate interface allows the user to query the most recent data by each sensor, listed out for an entire river basin: https://cdec.water.ca.gov/dynamicapp/getAll
CDECRetrieveFlowWest developed the R package CDECRetrieve for
querying CDEC data. This package is documented at https://github.com/FlowWest/CDECRetrieve
and can be installed via:
remotes::install_github("flowwest/CDECRetrieve")
The following section assesses spatial and temporal coverage of the stations.
The following chart summarizes the ranges of data availability. This is based on the published start and end dates and does not account for NA values within these ranges. Not listed in this figure because no stations are present: Bear Creek, Paynes Creek, Calaveras River.
check_for_overlap <- function(wy, chan, sec) {
cdec_station_sensors |>
filter(channel == chan & section == sec) |>
mutate(in_range = (wy >= min_wy) & (wy <= max_wy)) |>
pull(in_range) |>
any()
}
data_avail_by_water_year <-
expand_grid(water_year = seq(1949,2024,1),
manual_station_list |> select(channel, section) |> unique()) |>
mutate(has_data = pmap_lgl(list(water_year, channel, section), check_for_overlap))
data_avail_by_water_year |>
filter(!is.na(channel)) |>
ggplot() +
facet_grid(rows = vars(channel), scales="free_y", space="free_y") +
geom_tile(aes(x = factor(water_year), y = factor(section), fill = has_data)) +
xlab("Water Year") +
ylab("") +
theme_minimal() +
theme(legend.position = "top",
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
strip.text = element_blank(),
panel.margin=unit(0,"lines")) +
scale_y_discrete(limits=rev, position="right") +
scale_fill_manual(values = c("FALSE" = "white", "TRUE" = "darkgray"))
station_table <-
cdec_station_sensors |>
filter(mainstem) |>
group_by(channel, section, station_id, station_name) |>
summarize(start_date = min(start),
end_date = min(end),
sensors = list(unique(sensor_number)),
) |>
mutate(freq_avail = paste(map(sensors, function(x) if_else(20 %in% x, "hourly", "daily")))) |>
select(channel, section, station_id, station_name, start_date, end_date, freq_avail)
station_table |> write_csv("out/station_table.csv")
station_table |> st_drop_geometry() |> DT::datatable()
Also shown on this map for context are in-stream flow sensors on tributaries and secondary channels, as well as canal diversions and reservoir outflow gages.
watersheds_wgs84 <- st_transform(watershed_labels, "EPSG:4326")
flowlines_wgs84 <- st_transform(stream_flowlines, "EPSG:4326")
stations_wgs84 <- st_transform(cdec_stations, "EPSG:4326")
bypasses_wgs84 <- st_transform(filter(bypass_polys,name %in% c("Sutter Bypass", "Yolo Bypass")), "EPSG:4326")
#if (interactive()) {
leaflet::leaflet() |>
leaflet::addTiles(urlTemplate = 'https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}',
attribution = 'Basemap tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri',
options = leaflet::tileOptions(noWrap = TRUE, opacity = 1.0, maxNativeZoom = 13, maxZoom = 13)) |>
leaflet::addTiles(urlTemplate = 'https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Reference_Overlay/MapServer/tile/{z}/{y}/{x}',
attribution = 'Reference tiles © Esri — Source: USGS, Esri, TANA, DeLorme, and NPS',
options = leaflet::tileOptions(noWrap = TRUE, opacity = 0.5, maxNativeZoom = 13, maxZoom = 13)) |>
leaflet::addPolygons(data=watersheds_wgs84, label=~paste(river_basin, "watershed"), color="#888888", weight=1, fillOpacity = 0.0) |>
leaflet::addPolygons(data=bypasses_wgs84, label=~name, weight=0, fillColor="#2F88A6", fillOpacity=0.5, color=NA) |>
leaflet::addPolylines(data=flowlines_wgs84, label=~label, color="#2F88A6") |>
leaflet::addCircleMarkers(data=stations_wgs84,
label=~paste(str_to_upper(station_id), name, operator, paste(sensors), sep="<br>") |> lapply(htmltools::HTML),
color = ~if_else(mainstem, "#A6011F", "#888888"))